#ifndef MESH_MANAGER_H
#define MESH_MANAGER_H

#include "glew.h"
#include "vboModel.h"
#include "objMeshLoader.h"
#include "dataInModelConstants.h"
#include <string>
#include "logger.h"
#include "resourceManager.h"

using namespace std;


//! Menager modeli
/*!
	Menager modeli.
	Wszystkie funkcje ktore zwracaja bool zwracaja true jesli operacja sie udala, false wpp.
	Zawsze  mozna posluzyc sie funkcja GetLastError opisujaca zaistnialy blad:
*/
class MeshManager : public ResourceManager< VBOModel >
{
 typedef unsigned int uint;

 friend class Singleton< MeshManager >;

 public:

    //! Laduje model w formacie Obj
	/*!
		\param path scierzka do pliku *.obj z modelem
		\name nazwa pod jaka przetrzymywany bedzie model w managerze
		\return true jesli udalo sie zaladowac model, false wpp. W razie bledy mozna posluzyc sie GetLastError aby uzyskac wiecej informacji.
	*/
	bool LoadModel( const char* path, const char* name );

	//! Rysuje model
	/*!
		\param name nazwa wczesniej zaladowanego modelu
		\desiredData pozwala podac jakie dane powinny byc uzyte przy renderowaniu modelu.<BR>
		V_AND_VT_AND_VN_DATA - wierzcholki, wspolrzedne tesktur, normalne<BR>
		V_AND_VT_DATA		 - wierzcholki i wsp tekstur<BR>
		V_AND_VN_DATA		 - wierzcholki i normalne<BR>
		V_DATA				 - tylko wierzcholki<BR>
		Podanie odpowiedniej stalej nie spowoduje wygenerowania danych ktorych nie bylo w pliku z modelem.
		Np. jesli plik z modelem ma tylko informacje o wierzcholkach podanie stalej V_AND_VT_AND_VN_DATA
		nie spowoduje wygenerowania brakujacych danych o wsp tekstur (VT) i normalnych (VN). Parametr desiredData
		przyda sie nam tylko jesli wiemy ze mamy jakies dane i chcemy z nich swiadomie zrezygnowac (np nie potrzebujemy normalnych bo nie uzywamy swiatla) 
	
		\return true jesli sukces, false wpp. W razie bledy mozna posluzyc sie GetLastError aby uzyskac wiecej informacji.
	*/
	bool DrawModel( const char* name, DataInModel desiredData = V_AND_VT_AND_VN_DATA );


	//! Rysuje czesc modelu
	/*!
		Model w pliku Obj podzielony jest na grupy (g). Ta funkcja pozwoli nam wyrenderowac tylko dana grupe.
		Po co nam taka funkcja? Pozwala np. na przeiterowanie sie po elementach mesza i oteksturowanie kazdego elementu
		inna tekstura (np. drzewo - tekstura drewna na pien, trawy na korone)

		Grupy numerowane sa od 0, w takiej samej kolejnosci jak zapisane w pliku obj.

		\return true jesli sukces, false wpp. W razie bledy mozna posluzyc sie GetLastError aby uzyskac wiecej informacji.
	*/
	bool DrawModelElement( const char* key, uint elementNumber, DataInModel desiredData = V_AND_VT_AND_VN_DATA );

	//! Czysci managera
	void DeleteAll();

	//! Usuwa model z managera. 
	/*!
		\param name nazwa wczesniej zaladowanego modelu
		\return true jesli sukces, false wpp. W razie bledy mozna posluzyc sie GetLastError aby uzyskac wiecej informacji.
	*/
	const bool DeleteResource( const char* name );

	//! Pobiera ostatni blad 
	string GetLastError()
	{ return lastError; }

 private:

	ObjModel* pObjModel;
	ObjMeshLoader objMeshLoader;
	string lastError;

	void InitVBO();
	void DrawVBO( const uint& VBOid, const uint& numberOfVertices, const DataInModel& whichData, const int& polygonType );
	void DrawIthElement( const VBOModel* pVBOModel, const DataInModel& desiredData, const uint& ith  );

	bool RearangeData_v_vt_vn( ObjModel& objModel, VBOModel& vboModel );
	bool RearangeData_v_vt( ObjModel& objModel, VBOModel& vboModel );
	bool RearangeData_v_vn( ObjModel& objModel, VBOModel& vboModel );
	bool RearangeData_v( ObjModel& objModel, VBOModel& vboModel );

	~MeshManager()
	{ DeleteAll(); }

	MeshManager() { InitVBO(); }
	MeshManager(const MeshManager&) { }
	MeshManager& operator = (const MeshManager&) { }
	
};
#define MeshManagerAPI Singleton< MeshManager >::Instance()  


#endif